/*
 * Copyright (C) 2011-2013 Markus Junginger, greenrobot (http://greenrobot.de)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.intexh.quickandroid.module.chat.sprinkles;

import java.util.ArrayList;
import java.util.List;

public class QueryBuilder<T> {

    private StringBuilder orderBuilder;

    private final List<String> whereConditions;

    private final List<Object> values;
    private final Class dao;

    private int limit;

    private int offset;


    public static <T2 extends Model> QueryBuilder<T2> create(Class<T2> dao) {
        return new QueryBuilder<T2>(dao);
    }


    protected QueryBuilder(Class<T> dao) {
        this.dao = dao;
        values = new ArrayList<Object>();
        whereConditions = new ArrayList<String>();
    }

    /**
     * Adds the given conditions to the where clause using an logical AND. To create new conditions, use the properties
     * given in the generated dao classes.
     */
    public QueryBuilder<T> where(String cond) {
        whereConditions.add(cond);
        return this;
    }

    /**
     * Adds the given raw SQL string to the ORDER BY section. Do not use this for standard properties: ordedAsc and
     * orderDesc are prefered.
     */
    public QueryBuilder<T> order(String rawOrder) {
        if (orderBuilder == null) {
            orderBuilder = new StringBuilder();
        } else if (orderBuilder.length() > 0) {
            orderBuilder.append(",");
        }
        orderBuilder.append(rawOrder);
        return this;
    }

    /**
     * Limits the number of results returned by queries.
     */
    public QueryBuilder<T> limit(int limit) {
        this.limit = limit;
        return this;
    }

    public int getLimit() {
        return this.limit;
    }

    /**
     * Sets the offset for query results in combination with {@link #limit(int)}. The first {@code limit} results are
     * skipped and the total number of results will be limited by {@code limit}. You cannot use offset without limit.
     */
    public QueryBuilder<T> offset(int offset) {
        this.offset = offset;
        return this;
    }

    private String build() {
        StringBuilder builder = new StringBuilder("from ");
        builder.append(Utils.getTableName(dao));

        builder.append(" where 1 ");
        for (String where : whereConditions)
            builder.append(" and ").append(where);

        if (orderBuilder != null && orderBuilder.length() > 0) {
            builder.append(" ORDER BY ").append(orderBuilder);
        }

        if (limit > 0) {
            builder.append(" LIMIT ");
            builder.append(limit);
        }

        if (offset > 0) {
            if (limit == 0) {
                throw new IllegalStateException("Offset cannot be set without limit");
            }
            builder.append(" OFFSET ");
            builder.append(offset);
        }

        return builder.toString();
    }


    
    public List<T> list() {
        return Query.many(dao, "select * " + build()).get().asList();
    }

    public long count() {
        return Query.count("select count(*) recordCount " + build());
    }

}
